package cc.rengu.redp.bizimpl.manager;

import cc.rengu.redp.base.domain.router.RouterMeta;
import cc.rengu.redp.base.domain.router.VueRouter;
import cc.rengu.redp.bizimpl.constant.UpmpConstant;
import cc.rengu.redp.bizimpl.upmp.domain.UpmpMenu;
import cc.rengu.redp.bizimpl.upmp.domain.UpmpRole;
import cc.rengu.redp.bizimpl.upmp.domain.UpmpUserInfo;
import cc.rengu.redp.bizimpl.upmp.service.IUpmpCacheService;
import cc.rengu.redp.bizimpl.upmp.service.IUpmpMenuService;
import cc.rengu.redp.bizimpl.upmp.service.IUpmpRoleService;
import cc.rengu.redp.bizimpl.upmp.service.IUpmpUserInfoService;
import cc.rengu.redp.bizimpl.upmp.vo.UpmpUserInfoVO;
import cc.rengu.redp.bizimpl.utils.TreeUtil;
import cc.rengu.redp.common.domain.RedpConstant;
import cc.rengu.redp.common.exception.RedpException;
import cc.rengu.redp.common.redis.RedisService;
import cc.rengu.redp.common.utils.RedpUtil;
import cc.rengu.redp.system.domain.UserConfig;
import cc.rengu.redp.system.service.UserConfigService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.apache.ibatis.annotations.Param;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

/**
 * 封装一些和 User相关的业务操作
 */
@Service
public class UpmpUserManager {

    @Autowired
    private IUpmpCacheService upmpCacheService;
    @Autowired
    private IUpmpRoleService upmpRoleService;
    @Autowired
    private IUpmpMenuService upmpMenuService;
    @Autowired
    private IUpmpUserInfoService upmpUserService;
    @Autowired
    private UserConfigService userConfigService;
    @Autowired
    private RedisService redisService;


    /**
     * 通过用户名获取用户基本信息
     *
     * @param loginId 用户登录账户
     * @return 用户基本信息
     */
    public UpmpUserInfo getUser(String instId,String loginId) {
        return RedpUtil.selectCacheByTemplate(
                () -> this.upmpCacheService.getUser(instId,loginId),
                () -> this.upmpUserService.findByName(loginId));
    }

    /**
     * 通过用户名获取用户角色集合
     *
     * @param username 用户名
     * @return 角色集合
     */
    public Set<String> getUserRoleCodes(String username) {
        List<UpmpRole> roleList = RedpUtil.selectCacheByTemplate(
                () -> this.upmpCacheService.getRoles(username),
                () -> this.upmpRoleService.findUserRole(username));
        return roleList.stream().map(UpmpRole::getRoleCode).collect(Collectors.toSet());
    }
    /**
     * 通过用户名获取用户角色集合
     *
     * @param username 用户名
     * @return 角色集合
     */
    public Set<String> getUserRoles(String username) {
        List<UpmpRole> roleList = RedpUtil.selectCacheByTemplate(
                () -> this.upmpCacheService.getRoles(username),
                () -> this.upmpRoleService.findUserRole(username));
        return roleList.stream().map(UpmpRole::getRoleName).collect(Collectors.toSet());
    }

    /**
     * 通过用户名获取用户权限集合
     *
     * @param username 用户名
     * @return 权限集合
     */
    public Set<String> getUserPermissions(String username) {
        List<UpmpMenu> permissionList = RedpUtil.selectCacheByTemplate(
                () -> this.upmpCacheService.getPermissions(username),
                () -> this.upmpMenuService.findUserPermissions(username));
        return permissionList.stream().map(UpmpMenu::getPerms).collect(Collectors.toSet());
    }

    /**
     * 通过用户名构建 Vue路由
     *
     * @param userId 用户表非业务主键
     * @return 路由集合
     */
    public ArrayList<VueRouter<UpmpMenu>> getUserRouters(String userId,String channelType) throws Exception {
        List<VueRouter<UpmpMenu>> routes = new ArrayList<>();
        if (StringUtils.isEmpty(this.redisService.get(RedpConstant.USER_ROLE_CACHE_PREFIX + userId))) {
            this.upmpCacheService.saveRoles(userId);
        }
        List<UpmpRole> roles=this.upmpCacheService.getRoles(userId);
        int superAdmin = roles.stream().filter(role-> UpmpConstant.SYS_ROLE_SUPER_USER_ROLE_PARAM.equals(role.getRoleCode())).collect(Collectors.toList()).size();
        List<UpmpMenu> menus;
        if(superAdmin>0){//超管角色可以获取所有权限
            menus = this.upmpMenuService.list().stream().filter(menu->channelType.equals(menu.getChannelType())).collect(Collectors.toList());
        }else{
            menus = this.upmpMenuService.findUserMenus(userId);
            if(!ObjectUtils.isEmpty(menus)){
                menus = menus.stream().filter(menu->channelType.equals(menu.getChannelType())).collect(Collectors.toList());
            }
        }

        QueryWrapper<UpmpMenu> lqw = new QueryWrapper<>();
        lqw.eq("app_type", channelType);
        List<UpmpMenu> allUpmpMenus = upmpMenuService.list(lqw);
        Map<String,UpmpMenu> allUpmpMenuMap = new HashMap<>();
        allUpmpMenus.forEach(menu->{
            allUpmpMenuMap.put(menu.getId(),menu);
        });

        //页面需要的路由中只有菜单，没有按钮，而角色权限配置中只有叶子菜单或者按钮，需要转换将按钮转换成对应的菜单和对应菜单的层级关系，从而生成一棵前端的菜单路由树
        menus.forEach(menu -> {

            AtomicBoolean exist = new AtomicBoolean(false);
            routes.forEach(rout->{
                if(menu.getId().equals(rout.getId())){
                    exist.set(true);
                }
            });
            if(!exist.get()){
                if("0".equals(menu.getType())){//如果是菜单则直接添加到路由
                    VueRouter<UpmpMenu> route = new VueRouter<>();
                    route.setId(menu.getId());
                    route.setParentId(menu.getParentId());
                    route.setIcon(menu.getIcon());
                    route.setPath(menu.getPath());
                    route.setComponent(menu.getComponent());
                    route.setName(menu.getMenuName());
                    route.setMeta(new RouterMeta(true, null));
                    routes.add(route);
                    //同时向上递归上级菜单，并添加到路由中
                    if (!TreeUtil.TOP_NODE_ID.equals(menu.getParentId())) {
                        recursionParentsMenu(routes, allUpmpMenuMap, menu);
                    }

                }else{//如果是按钮则向上找菜单

                    //向上递归上级菜单，并添加到路由中
                    if (!TreeUtil.TOP_NODE_ID.equals(menu.getParentId())) {
                        recursionParentsMenu(routes, allUpmpMenuMap, menu);
                    }
                }
            }

        });
        return TreeUtil.buildVueRouter(routes);
    }

    /**
     *  根据叶子节点向上递归获取所有的菜单
     * @param routes
     * @param allUpmpMenuMap
     * @param menu
     */
    private void recursionParentsMenu(List<VueRouter<UpmpMenu>> routes,Map<String,UpmpMenu> allUpmpMenuMap,UpmpMenu menu){
        UpmpMenu parentMenu = allUpmpMenuMap.get(menu.getParentId());
        if(!ObjectUtils.isEmpty(parentMenu)){
            AtomicBoolean exist = new AtomicBoolean(false);
            routes.forEach(rout->{
                if(parentMenu.getId().equals(rout.getId())){
                    exist.set(true);
                }
            });
            if(!exist.get()){
                if("0".equals(parentMenu.getType())) {//如果是菜单则直接添加到路由
                    VueRouter<UpmpMenu> routeP = new VueRouter<>();
                    routeP.setId(parentMenu.getId());
                    routeP.setParentId(parentMenu.getParentId());
                    routeP.setIcon(parentMenu.getIcon());
                    routeP.setPath(parentMenu.getPath());
                    routeP.setComponent(parentMenu.getComponent());
                    routeP.setName(parentMenu.getMenuName());
                    routeP.setMeta(new RouterMeta(true, null));
                    routes.add(routeP);
                    //如果还不是顶级菜单，则继续向上递归上级菜单，并添加到路由中
                    if (!TreeUtil.TOP_NODE_ID.equals(parentMenu.getParentId())) {
                        recursionParentsMenu(routes, allUpmpMenuMap, parentMenu);
                    }
                }else{//如果是按钮则向上找菜单

                    //向上递归上级菜单，并添加到路由中
                    if (!TreeUtil.TOP_NODE_ID.equals(parentMenu.getParentId())) {
                        recursionParentsMenu(routes, allUpmpMenuMap, parentMenu);
                    }
                }
            }
        }
    }

    /**
     * 通过用户 ID获取前端系统个性化配置
     *
     * @param userId 用户 ID
     * @return 前端系统个性化配置
     */
    public UserConfig getUserConfig(String userId) {
        return RedpUtil.selectCacheByTemplate(
                () -> this.upmpCacheService.getUserConfig(userId),
                () -> this.userConfigService.findByUserId(userId));
    }

    /**
     * 将用户相关信息添加到 Redis缓存中
     *
     * @param user user
     */
    public void loadUserRedisCache(UpmpUserInfo user) throws Exception {
        // 缓存用户
        upmpCacheService.saveUser(user.getId());
        // 缓存用户角色
        upmpCacheService.saveRoles(user.getId());
        // 缓存用户权限
        upmpCacheService.savePermissions(user.getId());
        // 缓存用户个性化配置
        upmpCacheService.saveUserConfigs(String.valueOf(user.getUserId()));
    }


    /**
     * 将用户相关信息更新到 Redis缓存中
     *
     * @param user user
     */
    public void updateUserRedisCache(UpmpUserInfoVO user) throws Exception {
        // 缓存用户
        upmpCacheService.saveUser(user);
    }

    /**
     * 将用户角色和权限添加到 Redis缓存中
     *
     * @param userIds userIds
     */
    public void loadUserPermissionRoleRedisCache(List<String> userIds) throws Exception {
        for (String userId : userIds) {
            UpmpUserInfo user = upmpUserService.getById(userId);
            if(!ObjectUtils.isEmpty(user)){
                // 缓存用户角色
                upmpCacheService.saveRoles(user.getId());
                // 缓存用户权限
                upmpCacheService.savePermissions(user.getId());
            }
        }
    }

    /**
     * 通过用户 id集合批量删除用户 Redis缓存
     *
     * @param userIds userIds
     */
    public void deleteUserRedisCache(String... userIds) throws Exception {
        for (String userId : userIds) {
            UpmpUserInfo user = upmpUserService.getById(userId);
            if (user != null) {
                upmpCacheService.deleteUser(user.getId());
                upmpCacheService.deleteRoles(user.getId());
                upmpCacheService.deletePermissions(user.getId());
            }
            upmpCacheService.deleteUserConfigs(userId);
        }
    }

    /**
     * 获取数据库中用户基本信息
     * @param instId
     * @param userType
     * @param loginId
     * @return
     */
    public UpmpUserInfo getUser(@Param("instId") String instId, @Param("userType")String userType, @Param("loginId")String loginId)throws RedpException {
        return upmpUserService.findUpmpUserInfo(instId, userType, loginId);
    }


    /**
     * 获取数据库中用户基本信息
     * @param userId 用户表ID
     * @return
     */
    public UpmpUserInfo getUser(String userId)throws RedpException {
        return upmpUserService.findById(userId);
    }
}
